// let _this=typeof window !== "undefined" ? window : this

// let CACHE = {
// 	// 防抖 定时器
// 	timeout: null,
// 	// 节流 定时器
// 	timer: null,
// 	// 节流 标志
// 	flag: false,
// }

// let $pall = class {
// 	set(name, value, _window) {
// 		var cache = this.get(undefined, _window)
// 		if (typeof value == 'object' && value !== undefined) {
// 			let value_ = this.get(undefined, _window)[name] || undefined
// 			if (value_ != undefined) {
// 				if (value_.constructor === Array && value.constructor == Array) {
// 					value = $v.deepCopy(value_).concat($v.deepCopy(value))
// 				}
// 				if (value_.constructor === Object && value.constructor == Object) {
// 					value = Object.assign($v.deepCopy(value_), $v.deepCopy(value))
// 				}
// 			}
// 		}
// 		return value !== undefined ? cache[name] = value : cache
// 	}

// 	get(name, _window) {
// 		var top = _window !== undefined ? _window.top : window.top
// 		var cache = top ? (top['_CACHE'] || {}) : {}
// 		top ? top['_CACHE'] = cache : {}
// 		return name !== undefined && name !== '' ? cache[name] : cache
// 	}

// 	del(name, _window) {
// 		var cache = this.get(undefined, _window)
// 		if (cache && cache[name]) delete cache[name]
// 	}

// }

// let $v = class {
// 	constructor() {
// 		if (!_this.$) {
// 			console.error('初始化失败,请先加载JQ!')
// 			return
// 		}

// 		if (!_this.layui) {
// 			console.error('初始化失败,请先加载layer!')
// 			return
// 		}

// 		this.$p = new Map()
// 		this.$pall = new $pall()
// 	}


// }()


// export default $v;

// import $v from '$v';

;
! function(_this, func) {
	if (!_this.$) {
		console.error('初始化失败,请先加载JQ!')
		return
	}

	if (!_this.layui) {
		console.error('初始化失败,请先加载layer!')
		return
	}

	func(_this)
}(typeof window !== "undefined" ? window : this, function(_this) {
	// 内部参数
	let CACHE = {
		// 防抖 定时器
		timeout: null,
		// 节流 定时器
		timer: null,
		// 节流 标志
		flag: false,
	}
	// 全局固定 挂载
	_this.$v = {
		// 使用方法=>  可以挂载变量或方法  挂载变量时会全量替换值，不会在原有数据上增加
		// 本页面 挂载 方法2=>$v.$p.set('name',function(){})  调用=>$v.$p.get('name')()
		// 单个值全部删除 方法=>$v.$p.delete('name')
		$p: new Map(),
		// 使用方法=>  可以挂载变量或方法  挂载Array或Object默认会在原有数据上增加
		// 跨页面 挂载 方法1=>$v.$pall.set('name',function(){}) 调用=>$v.$pall.get().name()
		// 跨页面 挂载 方法2=>$v.$pall.set('name',function(){}) 调用=>$v.$pall.set().name()
		// 单个值全部删除 方法=>$v.$pall.del('name')
		// 单个值单个删除 方法=>delete $v.$pall.get()[name]
		$pall: new function() {
			this.set = function(name, value, _window) {
				var cache = this.get(undefined, _window)
				if (typeof value == 'object' && value !== undefined) {
					let value_ = this.get(undefined, _window)[name] || undefined
					if (value_ != undefined) {
						if (value_.constructor === Array && value.constructor == Array) {
							value = _this.$v.deepCopy(value_).concat(_this.$v.deepCopy(value))
						}
						if (value_.constructor === Object && value.constructor == Object) {
							value = Object.assign(_this.$v.deepCopy(value_), _this.$v.deepCopy(value))
						}
					}
				}
				return value !== undefined ? cache[name] = value : cache
			}
			this.get = function(name, _window) {
				var top = _window !== undefined ? _window.top : window.top
				var cache = top ? (top['_CACHE'] || {}) : {}
				top ? top['_CACHE'] = cache : {}
				return name !== undefined && name !== '' ? cache[name] : cache
			}
			this.del = function(name, _window) {
				var cache = this.get(undefined, _window)
				if (cache && cache[name]) delete cache[name]
			}
		},
		request: function(action, type = 'GET', field = {}, errMsgBool = true, dataType = 'JSON',
			receiveType = 'JSON', Header = {}, defErrMsg = '请求失败', wait, timeout = 5000, dataToJsonStr =
			false
		) {
			// 认定请求成功时,返回[请求结果数据](单单数据内容)
			// 认定请求失败时,返回[整体请求结构](包含协议头，状态码等)
			// 同步使用async await
			// 异步使用then
			return new function() {
				let this_ = this
				// 请求地址
				this.action = action
				// 请求类型
				this.type = type
				// 携带数据
				this.field = field
				// 请求失败时是否提示信息
				this.errMsgBool = errMsgBool
				// 数据类型
				this.dataType = dataType
				// 接收数据类型
				this.receiveType = receiveType
				// 携带Header
				this.Header = Header
				// 请求失败时,返回数据找不到失败字段时,默认提示文本
				this.defErrMsg = defErrMsg
				// 是否请求中,显示等待弹框
				this.wait = wait
				// 超时时间
				this.timeout = timeout
				// 携带数据 是否转换Json字符串类型
				this.dataToJsonStr = dataToJsonStr

				// 统一默认配置
				this.config = {
					// 前缀地址
					baseUrl: 'https://www.gongjubaike.cn',
					// 固定数据 (只有dataType为json时会携带)
					data: {},
					// 固定协议头
					Header: {
						'content-type': 'application/json;charset=UTF-8',
					},
					// 请求开始 输出提示
					startlog: false,
					// 请求结束 输出提示
					endlog: false
				}

				// 每次请求前都会执行本方法
				this.start = function() {
					if (this.config.startlog) console.log('请求开始', this)

					// 自适应调试方法
					if (window.location.hostname.indexOf('localhost') != -1) this.config.baseUrl =
						'http://localhost:8080'
					if (window.location.hostname.indexOf('127.0.0.1') != -1) this.config.baseUrl =
						'http://localhost:8080'
				}
				// 每次请求结束都会执行本方法
				this.end = function(res) {
					if (this.config.startlog) console.log('请求结束', this, res)

					if (res.status == 200) {
						let data = dataToType(res.responseText)

						if (data.code == 0) return true;

						switch (parseInt(data.code)) {
							// case 999999999:
							// 	return false;
							// 	break;
							default:
								if (this.errMsgBool) _this.$v.prompt.error(data.msg ? data.msg : this
									.defErrMsg)
						}

						return false
					} else {

						switch (res.status) {
							// case 999999999:
							// 	return false;
							// 	break;
							default:
								if (this.errMsgBool) _this.$v.prompt.error(data.msg ? data.msg : this
									.defErrMsg)
						}

					}

					// 公共区开始-------->>>>



					return false
				}
				this.send = function() {
					this.start()
					if (this.wait) {
						try {
							var loading = layer.load(1, {
								shade: [0.1, '#fff'],
								time: this.timeout
							})
						} catch (e) {

						}
					}
					let sendData = this.dataType.toLowerCase() == 'json' ? Object.assign(
						this.config.data, this.field) : this.field
					if (this.dataToJsonStr) sendData = JSON.stringify(sendData)
					return new Promise((resolve, reject) => {
						$.ajax({
							type: this.type,
							url: this.config.baseUrl + this.action,
							// contentType: 'application/json;charset=UTF-8',
							data: sendData,
							async: false,
							timeout: this.timeout,
							dataType: this.dataType,
							headers: this.config.Header,
							beforeSend: (XMLHttpRequest) => {
								for (let i in this.Header) {
									XMLHttpRequest.setRequestHeader(i, this
										.Header[i])
								}
							},
							success: (data, textStatus, xhr) => {
								if (this.end(xhr)) resolve(dataToType(xhr
									.responseText));
								else reject(xhr);
							},
							error: (xhr, textStatus) => {
								if (this.end(xhr)) resolve(dataToType(xhr
									.responseText));
								else reject(xhr);
							},
							complete: (xhr, textStatus) => {
								if (this.wait && loading) {
									try {
										layer.close(loading)
									} catch (e) {

									}
								}
							}
						})
					});
				}
				// 数据解析 返回对象类型
				function dataToType(val) {
					try {
						switch (this_.receiveType.toLowerCase()) {
							case 'json':
								return JSON.parse(val)
								break
							case 'xml':
								return _this.$v.xmlStrToJson(val)
								break
						}
					} catch (e) {

					}

					return {}
				}
				this.setType = function(val) {
					this.type = val
					return this
				}
				this.setErrMsgBool = function(val) {
					this.errMsgBool = val
					return this
				}
				this.setDataType = function(val) {
					this.dataType = val
					return this
				}
				this.setReceiveType = function(val) {
					this.receiveType = val
					return this
				}
				this.setHeader = function(val) {
					this.Header = val
					return this
				}
				this.setDefErrMsg = function(val) {
					this.defErrMsg = val
					return this
				}
				this.setWait = function(val) {
					this.wait = val
					return this
				}
				this.setTimeout = function(val) {
					this.timeout = val
					return this
				}
				this.setDataToJsonStr = function(val) {
					this.dataToJsonStr = val
					return this
				}
			}
		},
		GetArray: function(arr) {
			// Array类型 自方法
			return new function() {
				this.arr = JSON.parse(JSON.stringify(arr))

				// 查询指定内容且删除掉它
				this.indexOfSplice = function(val) {
					let index = this.arr.indexOf(val)
					// let index=-1
					// for (let i = 0; i < addlsit.length; i++) {
					// 	if(addlsit[i]==obj.data.title){
					// 		index=i
					// 		break
					// 	}
					// }
					if (index == -1) return this.arr
					else this.arr.splice(index, 1)
					return this
				}

				// 内置固定方法 开始区===>>>>  (放在底部,防止自定义挂载方法中有重复，不失效问题)
				this.get = function() {
					return this.arr
				}


			}
		},
		prompt: {
			success: function(val) {
				_this.layui.use(['table'], function() {
					layer.msg(val, {
						icon: 1,
						time: 1500
					});
				})
			},
			warn: function(val) {
				_this.layui.use(['table'], function() {
					layer.msg(val, {
						icon: 0,
						time: 2000
					});
				})
			},
			error: function(val) {
				_this.layui.use(['table'], function() {
					layer.msg(val, {
						icon: 2,
						time: 2000
					});
				})
			}
		},
		deepCopy: function(source) {
			// 深度克隆
			if (typeof source != "object") {
				return source;
			}
			if (source == null) {
				return source;
			}
			var newObj = source.constructor === Array ? [] : {};
			for (var i in source) {
				newObj[i] = _this.$v.deepCopy(source[i]);
			}
			return newObj;
		},
		getUrlParam: function(variable) {
			// 从url获取值
			var query = window.location.search.substring(1);
			var vars = query.split("&");
			for (var i = 0; i < vars.length; i++) {
				var pair = vars[i].split("=");
				if (pair[0] == variable) {
					return pair[1];
				}
			}
			return (false);
		},
		print: function() {
			// 输出信息
			return new function() {
				// 阻止输出配置
				this.config = {
					logon: false,
					infoon: false,
					warnon: false,
					erroron: false
				}

				this.log = function(...val) {
					if (this.config.logon) return
					console.log(...val);
				}
				this.info = function(...val) {
					if (this.config.infoon) return
					console.info(...val);
				}
				this.warn = function(...val) {
					if (this.config.warnon) return
					console.warn(...val);
				}
				this.error = function(...val) {
					if (this.config.erroron) return
					console.error(...val);
				}
			}
		},
		xmlStrToXml: function(xmlStr) {
			// xml字符串转换xml对象数据
			var xmlObj = {};
			if (document.all) {
				var xmlDom = new ActiveXObject("Microsoft.XMLDOM");
				xmlDom.loadXML(xmlStr);
				xmlObj = xmlDom;
			} else {
				xmlObj = new DOMParser().parseFromString(xmlStr, "text/xml");
			}
			return xmlObj;
		},
		xmlStrToJson: function(xml) {
			// xml字符串转换json数据
			var xmlObj = _this.$v.xmlStrToXml(xml);
			var jsonObj = {};
			if (xmlObj.childNodes.length > 0) {
				jsonObj = _this.$v.xmlTojson(xmlObj);
			}
			return jsonObj;
		},
		xmlTojson: function(xml) {
			// xml转换json数据
			try {
				var obj = {};
				if (xml.children.length > 0) {
					for (var i = 0; i < xml.children.length; i++) {
						var item = xml.children.item(i);
						var nodeName = item.nodeName;
						if (typeof(obj[nodeName]) == "undefined") {
							obj[nodeName] = _this.$v.xmlTojson(item);
						} else {
							if (typeof(obj[nodeName].push) == "undefined") {
								var old = obj[nodeName];
								obj[nodeName] = [];
								obj[nodeName].push(old);
							}
							obj[nodeName].push(_this.$v.xmlTojson(item));
						}
					}
				} else {
					obj = xml.textContent;
				}
				return obj;
			} catch (e) {
				// console.log(e.message);
				return {}
			}
		},
		timeFormat: function(dateTime = null, fmt = 'yyyy-mm-dd') {
			// yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合

			// 如果为null,则格式化当前时间
			if (!dateTime) dateTime = Number(new Date());
			// 如果dateTime长度为10或者13，则为秒和毫秒的时间戳，如果超过13位，则为其他的时间格式
			if (dateTime.toString().length == 10) dateTime *= 1000;
			let date = new Date(dateTime);
			let ret;
			let opt = {
				"y+": date.getFullYear().toString(), // 年
				"m+": (date.getMonth() + 1).toString(), // 月
				"d+": date.getDate().toString(), // 日
				"h+": date.getHours().toString(), // 时
				"M+": date.getMinutes().toString(), // 分
				"s+": date.getSeconds().toString() // 秒
				// 有其他格式化字符需求可以继续添加，必须转化成字符串
			};
			for (let k in opt) {
				ret = new RegExp("(" + k + ")").exec(fmt);
				if (ret) {
					fmt = fmt.replace(ret[1], (ret[1].length == 1) ? (opt[k]) : (opt[k].padStart(ret[1]
						.length,
						"0")))
				};
			};
			return fmt;
		},
		guid: function(len = 32, firstU = true, radix = null) {
			/**
			 * 本算法来源于简书开源代码，详见：https://www.jianshu.com/p/fdbf293d0a85
			 * 全局唯一标识符（uuid，Globally Unique Identifier）,也称作 uuid(Universally Unique IDentifier) 
			 * @param {Number} len uuid的长度
			 * @param {Boolean} firstU 将返回的首字母置为"u"
			 * @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制
			 */

			let chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
			let uuid = [];
			radix = radix || chars.length;

			if (len) {
				// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
				for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
			} else {
				let r;
				// rfc4122标准要求返回的uuid中,某些位为固定的字符
				uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
				uuid[14] = '4';

				for (let i = 0; i < 36; i++) {
					if (!uuid[i]) {
						r = 0 | Math.random() * 16;
						uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
					}
				}
			}
			// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
			if (firstU) {
				uuid.shift();
				return 'u' + uuid.join('');
			} else {
				return uuid.join('');
			}
		},
		deepClone: function(obj) {
			// 深度克隆

			// 对常见的“非”值，直接返回原来值
			if ([null, undefined, NaN, false].includes(obj)) return obj;
			if (typeof obj !== "object" && typeof obj !== 'function') {
				//原始类型直接返回
				return obj;
			}
			var o = _this.$v.is.array(obj) ? [] : {};
			for (let i in obj) {
				if (obj.hasOwnProperty(i)) {
					o[i] = typeof obj[i] === "object" ? _this.$v.deepClone(obj[i]) : obj[i];
				}
			}
			return o;
		},
		deepMerge: function(target = {}, source = {}) {
			// JS对象深度合并

			target = _this.$v.deepClone(target);
			if (typeof target !== 'object' || typeof source !== 'object') return false;
			for (var prop in source) {
				if (!source.hasOwnProperty(prop)) continue;
				if (prop in target) {
					if (typeof target[prop] !== 'object') {
						target[prop] = source[prop];
					} else {
						if (typeof source[prop] !== 'object') {
							target[prop] = source[prop];
						} else {
							if (target[prop].concat && source[prop].concat) {
								target[prop] = target[prop].concat(source[prop]);
							} else {
								target[prop] = _this.$v.deepMerge(target[prop], source[prop]);
							}
						}
					}
				} else {
					target[prop] = source[prop];
				}
			}
			return target;
		},
		random: function(min, max) {
			// 随机数

			if (min >= 0 && max > 0 && max >= min) {
				let gab = max - min + 1;
				return Math.floor(Math.random() * gab + min);
			} else {
				return 0;
			}
		},
		trim: function(str, pos = 'both') {
			// 去除空格

			if (pos == 'both') {
				return str.replace(/^\s+|\s+$/g, "");
			} else if (pos == "left") {
				return str.replace(/^\s*/, '');
			} else if (pos == 'right') {
				return str.replace(/(\s*$)/g, "");
			} else if (pos == 'all') {
				return str.replace(/\s+/g, "");
			} else {
				return str;
			}
		},
		debounce: function(func, wait = 500, immediate = false, ...val) {
			// 防抖,一定时间内，只有最后一次操作，再过wait毫秒后才执行函数
			// func 要执行的回调函数 
			// wait 延时的时间
			// immediate 是否立即执行 

			// 清除定时器
			if (CACHE.timeout !== null) clearTimeout(CACHE.timeout);
			// 立即执行，此类情况一般用不到
			if (immediate) {
				var callNow = !CACHE.timeout;
				CACHE.timeout = setTimeout(function() {
					CACHE.timeout = null;
				}, wait);
				if (callNow) typeof func === 'function' && func(...val);
			} else {
				// 设置定时器，当最后一次操作后，timeout不会再被清除，所以在延时wait毫秒后执行func回调方法
				CACHE.timeout = setTimeout(function() {
					typeof func === 'function' && func(...val);
				}, wait);
			}
		},
		throttle: function(func, wait = 500, immediate = true, ...val) {
			// 节流,在一定时间内，只能触发一次
			// func 要执行的回调函数 
			// wait 延时的时间
			// immediate 是否立即执行

			if (immediate) {
				if (!CACHE.flag) {
					CACHE.flag = true;
					// 如果是立即执行，则在wait毫秒内开始时执行
					typeof func === 'function' && func(...val);
					CACHE.timer = setTimeout(() => {
						CACHE.flag = false;
					}, wait);
				}
			} else {
				if (!CACHE.flag) {
					CACHE.flag = true
					// 如果是非立即执行，则在wait毫秒内的结束处执行
					CACHE.timer = setTimeout(() => {
						CACHE.flag = false
						typeof func === 'function' && func(...val);
					}, wait);
				}
			}
		},



		is: {
			// 校验规则

			email: function(value) {
				// 验证电子邮箱格式
				return /[\w!#$%&'*+/=?^_`{|}~-]+(?:\.[\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[\w](?:[\w-]*[\w])?/
					.test(value);
			},
			mobile: function(value) {
				// 验证手机格式
				return /^1[3-9]\d{9}$/.test(value)
			},
			url: function(value) {
				// 验证URL格式
				return /http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-.\/?%&=]*)?/.test(value)
			},
			date: function(value) {
				// 验证日期格式
				return !/Invalid|NaN/.test(new Date(value).toString())
			},
			dateISO: function(value) {
				// 验证ISO类型的日期格式
				return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
			},
			number: function(value) {
				// 验证十进制数字
				return /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value)
			},
			digits: function(value) {
				// 验证整数
				return /^\d+$/.test(value)
			},
			idCard: function(value) {
				// 验证身份证号码
				return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
					value)
			},
			carNo: function(value) {
				// 是否车牌号

				// 新能源车牌
				const xreg =
					/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/;
				// 旧车牌
				const creg =
					/^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/;
				if (value.length === 7) {
					return creg.test(value);
				} else if (value.length === 8) {
					return xreg.test(value);
				} else {
					return false;
				}
			},
			amount: function(value) {
				// 金额,只允许2位小数

				//金额，只允许保留两位小数
				return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value);
			},
			chinese: function(value) {
				// 中文
				let reg = /^[\u4e00-\u9fa5]+$/gi;
				return reg.test(value);
			},
			letter: function(value) {
				// 只能输入字母
				return /^[a-zA-Z]*$/.test(value);
			},
			enOrNum: function(value) {
				// 只能是字母或者数字

				//英文或者数字
				let reg = /^[0-9a-zA-Z]*$/g;
				return reg.test(value);
			},
			contains: function(value, param) {
				// 验证是否包含某个值
				return value.indexOf(param) >= 0
			},
			range: function(value, param) {
				// 验证一个值范围[min, max]
				return value >= param[0] && value <= param[1]
			},
			rangeLength: function(value, param) {
				// 验证一个长度范围[min, max]
				return value.length >= param[0] && value.length <= param[1]
			},
			landline: function(value) {
				// 是否固定电话
				let reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/;
				return reg.test(value);
			},
			empty: function(value) {
				// 判断是否为空
				switch (typeof value) {
					case 'undefined':
						return true;
					case 'string':
						if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true;
						break;
					case 'boolean':
						if (!value) return true;
						break;
					case 'number':
						if (0 === value || isNaN(value)) return true;
						break;
					case 'object':
						if (null === value || value.length === 0) return true;
						for (var i in value) {
							return false;
						}
						return true;
				}
				return false;
			},
			jsonString: function(value) {
				// 是否json字符串
				if (typeof value == 'string') {
					try {
						var obj = JSON.parse(value);
						if (typeof obj == 'object' && obj) {
							return true;
						} else {
							return false;
						}
					} catch (e) {
						return false;
					}
				}
				return false;
			},
			array: function(value) {
				// 是否数组
				if (typeof Array.isArray === "function") {
					return Array.isArray(value);
				} else {
					return Object.prototype.toString.call(value) === "[object Array]";
				}
			},
			object: function(value) {
				// 是否对象
				return Object.prototype.toString.call(value) === '[object Object]';
			},
			code: function(value, len = 6) {
				// 是否短信验证码
				return new RegExp(`^\\d{${len}}$`).test(value);
			},



		},



	}

})
